package com.panfeng.xcloud.boss.provider.member.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.panfeng.xcloud.boss.provider.member.cache.CacheContext;
import com.panfeng.xcloud.boss.provider.member.dao.mapper.UserAccountMapperExt;
import com.panfeng.xcloud.boss.provider.member.dto.request.LoginReqDTO;
import com.panfeng.xcloud.boss.provider.member.dto.response.LoginTokenResponseDTO;
import com.panfeng.xcloud.boss.provider.member.enums.LoginModeEnum;
import com.panfeng.xcloud.boss.provider.member.service.ISeqenceService;
import com.panfeng.xcloud.boss.provider.member.service.IUserTokenService;
import com.panfeng.xcloud.boss.provider.member.utils.TokenRequestUtils;
import com.panfeng.xcloud.common.core.constants.GlobalConstant;
import com.panfeng.xcloud.common.core.enums.ResponseStatusEnum;
import com.panfeng.xcloud.common.core.exceptions.BaseBizException;
import com.panfeng.xcloud.common.core.thread.ThreadLocalMap;
import com.panfeng.xcloud.common.core.utils.StringUtils;
import com.panfeng.xcloud.common.core.web.vo.ResponseVO;
import com.panfeng.xcloud.common.security.vo.SysSecurityUser;
import com.panfeng.xcloud.dao.member.entity.UserBase;
import com.panfeng.xcloud.dao.member.mapper.ImUserMapper;
import com.panfeng.xcloud.im.model.TLSSigAPIv6;
import com.panfeng.xcloud.im.util.SnowflakeIdUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.Executor;

/**
 *
 * 用户token业务service
 *
 * @author xiaobo
 * @version 1.0
 * @since 2018-12-28
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class UserTokenServiceImpl implements IUserTokenService {

	@Value("${xdcloud.auth.refresh-token-url}")
	private String refreshTokenUrl;

	@Value("${xdcloud.auth.verifycode-token-url}")
	private String verifycodeTokenUrl;

	@Value("${xdcloud.auth.password-token-url}")
	private String passwordTokenUrl;

	@Autowired
	private TokenStore tokenStore;

	@Autowired
	private CacheContext cacheContext;

	@Autowired
	private UserAccountMapperExt userAccountMapperExt;

	@Autowired
	private ISeqenceService iSeqenceService;

	@Autowired
	@Qualifier("asyncExecutor")
	private Executor executor;

	@Resource
	private TLSSigAPIv6 tlsSigAPIv6;

	@Resource
	private ImUserMapper imUserMapper;

	private final static SnowflakeIdUtil snowflakeIdUtil = new SnowflakeIdUtil(1,1);

	@Override
	public String refreshToken(String clientId,String clientSecret , String refreshToken, HttpServletRequest request){
		String token = TokenRequestUtils.refreshToken(refreshTokenUrl,clientId,clientSecret,refreshToken,request);
		JSONObject jsonObj = JSON.parseObject(token);
		if(null != jsonObj){
			String accessTokenNew = (String) jsonObj.get("access_token");
			String refreshTokenNew = (String) jsonObj.get("refresh_token");
			String loginName = (String) jsonObj.get("loginName");
			log.info(">>> 当前刷新的token信息accessTokenNew={}，refreshTokenNew={}，loginName={} <<<",accessTokenNew,refreshTokenNew,loginName);
		}
		return token;
	}

	/**
	 * 登录获取token通过验证码进行登录
	 *
	 * @param loginModeEnum
	 * @param loginReqDTO
	 * @param request
	 * @return
	 */
	@Override
	public LoginTokenResponseDTO loginToken(LoginModeEnum loginModeEnum, LoginReqDTO loginReqDTO, HttpServletRequest request) {
		LoginTokenResponseDTO loginTokenResponseDto = new LoginTokenResponseDTO();
		String tokenInfo = "";

		if(loginModeEnum.getValue().equals(LoginModeEnum.LOGIN_MODE_VERIFY_CODE.getValue())){
			log.info(">>> 开始进行手机验证码模式登录，请求参数信息：{}<<<",(null != loginReqDTO?JSON.toJSONString(loginReqDTO):""));
			tokenInfo = TokenRequestUtils.verifyCodeLogin(verifycodeTokenUrl, loginReqDTO.getClientId(), loginReqDTO.getClientSecret(), loginReqDTO.getAccountNumber(),loginReqDTO.getVerifyCode(), request);
		}else{
			log.info(">>> 开始进行密码模式登录，请求参数信息：{}<<<",(null != loginReqDTO?JSON.toJSONString(loginReqDTO):""));
			tokenInfo = TokenRequestUtils.pwdLogin(passwordTokenUrl, loginReqDTO.getClientId(), loginReqDTO.getClientSecret(), loginReqDTO.getAccountNumber(),loginReqDTO.getPassword(), request);
		}
		if(StringUtils.isEmpty(tokenInfo)){
			log.error(">>> 登录oauth2认证中心鉴权失败，返回的信息为空<<<");
			throw new BaseBizException(ResponseStatusEnum.UNAUTHORIZED);
		}

		JSONObject tokenInfoJsonObj = JSON.parseObject(tokenInfo);
		if(null != tokenInfoJsonObj){
			ResponseVO response = tokenInfoJsonObj.toJavaObject(ResponseVO.class);
			if(!response.getCode().equals(ResponseStatusEnum.OK.getCode())){
				log.error(">>> 登录oauth2认证中心鉴权失败,鉴权错误信息：{}<<<",tokenInfo);
				throw new BaseBizException(ResponseStatusEnum.LOGINTOKEN_REQUEST_FAIL ,response.getMessage());
			}
			Object data = response.getData();
			if(data == null){
				log.error(">>> 登录oauth2认证中心鉴权失败,鉴权错误信息：{}<<<",tokenInfo);
				throw new BaseBizException(ResponseStatusEnum.LOGINTOKEN_REQUEST_FAIL);
			}
			JSONObject tokenInfoDataJsonObj = JSONObject.parseObject(JSONObject.toJSONString(data));
			if(tokenInfoDataJsonObj == null){
				log.error(">>> 登录oauth2认证中心鉴权失败,鉴权错误信息：{}<<<",tokenInfo);
				throw new BaseBizException(ResponseStatusEnum.LOGINTOKEN_REQUEST_FAIL);
			}
			//{"error":"invalid_grant","error_description":"坏的凭证"}
			//{"error":"invalid_grant","error_description":"Bad credentials"}
			if(tokenInfoDataJsonObj.containsKey("error") || "invalid_grant".equals(tokenInfoDataJsonObj.getString("error"))){
				log.error(">>> 登录oauth2认证中心鉴权失败,鉴权错误信息：{}<<<",tokenInfo);
				throw new BaseBizException(ResponseStatusEnum.LOGINTOKEN_REQUEST_FAIL);
			}
			if(!tokenInfoDataJsonObj.containsKey("access_token")){
				log.error(">>> 登录oauth2认证中心鉴权失败,鉴权错误信息：{}<<<",tokenInfo);
				throw new BaseBizException(ResponseStatusEnum.LOGINTOKEN_REQUEST_FAIL);
			}

			String access_token = (String) tokenInfoDataJsonObj.get("access_token");
			String token_type = (String) tokenInfoDataJsonObj.get("token_type");
			String refresh_token = (String) tokenInfoDataJsonObj.get("refresh_token");
			Integer expires_in = (Integer) tokenInfoDataJsonObj.get("expires_in");
			String scope = (String) tokenInfoDataJsonObj.get("scope");

			loginTokenResponseDto.setAccess_token(access_token);
			loginTokenResponseDto.setExpires_in(expires_in);
			loginTokenResponseDto.setRefresh_token(refresh_token);
			loginTokenResponseDto.setScope(scope);
			loginTokenResponseDto.setToken_type(token_type);

			log.info(">>> 当前获取的token信息access_token={}，token_type={}，refresh_token={}，expires_in={}，scope={} <<<",access_token,token_type,refresh_token,expires_in,scope);
			return loginTokenResponseDto;
		}else{
			log.error(">>> 登录oauth2认证中心鉴权失败,鉴权错误信息：{}<<<",tokenInfo);
			throw new BaseBizException(ResponseStatusEnum.LOGINTOKEN_REQUEST_FAIL);
		}
	}

	/**
	 * 设置token失效
	 *
	 * @param accessToken
	 */
	@Override
	public void expireToken(String accessToken) {
		//jwtTokenStore无效
		OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(accessToken);
		if(null != oAuth2AccessToken){
			tokenStore.removeAccessToken(oAuth2AccessToken);
		}
		// 获取用户信息
		SysSecurityUser securityUser = cacheContext.getSysSecurityUserInfoForCacheByToken(accessToken);

		// 移除用户登录信息
		cacheContext.removeLoginUserInfo(accessToken);
		ThreadLocalMap.remove(GlobalConstant.Sys.TOKEN_AUTH_DTO);

		// 移除userId绑定信息
		cacheContext.removeAccessTokenForUserId(securityUser.getUserId().toString());
	}

	/**
	 * 处理认证后数据
	 *
	 * @param loginTokenResponseDto
	 * @param sysSecurityUser
	 * @param request
	 */
	@Override
	public void authAfterHandleData(LoginTokenResponseDTO loginTokenResponseDto, SysSecurityUser sysSecurityUser, HttpServletRequest request, UserBase userBase) {
		log.info(">>> 开始处理认证后数据，userId={} <<<",sysSecurityUser.getUserId());
		String accessToken = loginTokenResponseDto.getAccess_token();
		Integer accessTokenValidateSeconds = loginTokenResponseDto.getExpires_in() == null? -1 : loginTokenResponseDto.getExpires_in();
		//存储当前用户到redis中
		cacheContext.cacheUserInfoForToken(accessToken,accessTokenValidateSeconds,sysSecurityUser);
	}

}
